import fs from 'fs/promises';
import path from 'path';
import cp from 'child_process';
import * as esbuild from 'esbuild';
import chokidar from 'chokidar';
import { fileURLToPath } from 'url';
import electron from 'electron';
import livereload from 'livereload';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/**
 * @type {ChildProcess}
 */
let electronCP = null;
const liveServer = livereload.createServer({port: 35729});

const fsExists = async (path) => {
    const {promise, resolve} = Promise.withResolvers();
    fs.stat(path).then(() => resolve(true)).catch(() => resolve(false));
};

// 打包主进程与创建index.html文件
const buildElectron = async () => {
    await esbuild.build({
        entryPoints: ['./master/index.ts'],
        outfile: './dist/master.js',
        platform: 'node',
        bundle: true,
        external: ['electron'],
        format: 'esm',
    });
    if (!await fsExists('./dist/renderer')) {
        await fs.writeFile('./dist/index.html', `
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta http-equiv="X-UA-Compatible" content="IE=edge">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>Electron App</title>
            </head>
            <body>
                <script>
                    const script = document.createElement('script');
                    script.src = 'http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1';
                    document.body.appendChild(script);
                </script>
                <script src="./render.js"></script>
            </body>
            </html>
        `);
    }
};

// 打包渲染进程
const buildRender = async () => {
    await esbuild.build({
        entryPoints: ['./render/index.ts'],
        outfile: './dist/render.js',
        platform: 'browser',
        bundle: true,
    });
};

// 打包preload
const buildPreload = async () => {
    await esbuild.build({
        entryPoints: ['./preload/index.ts'],
        outfile: './dist/preload.js',
        platform: 'node',
        bundle: true,
        external: ['electron'],
        format: 'cjs',
    });
};

// 启动Electron
const startElectron = () => {
    electronCP = cp.spawn(electron, [path.join(__dirname, 'dist/master.js')]);
    electronCP.stdout.on('data', (chunk) => {
        process.stdout.write(`[master] ${chunk}`);
    });
    electronCP.stderr.on('data', (chunk) => {
        process.stderr.write(`[master ERR] ${chunk}`);
    });
    electronCP.once('close', process.exit);
};

await buildElectron();
await buildPreload();
await buildRender();
startElectron();

chokidar.watch('./master').on('change', async () => {
    await buildElectron();
    electronCP.removeAllListeners();
    electronCP.once('exit', startElectron);
    electronCP.kill();
});

chokidar.watch('./render').on('change', async () => {
    await buildRender();
    liveServer.refresh('/');
});

chokidar.watch('./preload').on('change', async () => {
    await buildPreload();
    liveServer.refresh('/');
});